package jee.boot.module.bpm.service;

import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import jee.boot.common.basic.Page;
import jee.boot.entity.system.Filter;
import jee.boot.common.properties.ProjectConfig;
import jee.boot.common.remote.RemoteEndpoint;
import jee.boot.common.standard.DocumentStorageClient;
import jee.boot.common.utils.JsonMapper;
import jee.boot.common.utils.MapUtils;
import jee.boot.common.utils.StringUtils;
import jee.boot.entity.bpm.*;
import jee.boot.entity.file.Attachment;
import jee.boot.entity.file.AttachmentMapping;
import jee.boot.entity.task.ExcelUtils;
import jee.boot.entity.task.IexpTask;
import jee.boot.module.bpm.dao.BusinessDataDao;
import jee.boot.module.bpm.delegated.BusinessDataTemplate;
import jee.boot.module.bpm.validation.DataValidationHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 业务表数据
 */
@Service
public class BusinessDataService {
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private BusinessDataDao dao;
    @Autowired
    private FormDefinitionService formDefinitionService;
    @Autowired
    private BusinessDataTemplate businessDataTemplate;
    @Autowired
    private DocumentStorageClient documentStorageClient;
    @Autowired
    private RemoteEndpoint remoteEndpoint;
    @Autowired
    private ProjectConfig projectConfig;

    /**
     * 查看数据
     *
     * @param entity
     * @return
     */
    public BusinessData get(BusinessData entity) {
        FormDefinition definition = formDefinitionService.getCompleteDataByName(entity.getDefinition());
        if (definition != null) {
            entity.configDefinition(definition);
            entity.preQuery();
            Map<String, Object> map = dao.get(entity);
            entity.postQuery(map);
            entity.setData(map);
            // 加载关联数据
            if (map != null) {
                loadRelationData(entity);
            }

        }
        return entity;
    }

    public Page<Map<String, Object>> findPage(BusinessData entity) {
        FormDefinition definition = formDefinitionService.getCompleteDataByName(entity.getDefinition());
        Page<Map<String, Object>> pageData = new Page<>();
        if (definition != null) {
            entity.configDefinition(definition);
            Page<BusinessData> page = entity.getPage();
            if (page == null) {
                page = new Page<BusinessData>(1, 10);
                entity.setPage(page);
            }
            if (page.getPageSize() < 0) {
                page.setPageSize(0);
            }
            entity.preQuery();
            com.github.pagehelper.Page<Map<String, Object>> startPage = PageHelper.startPage(page.getPageNo(), page.getPageSize(), true, true, true);
            List<Map<String, Object>> listData = dao.findList(entity);
            entity.postQuery(listData);
            entity.setList(listData);
            pageData.setList(entity.getList());
            pageData.setCount(startPage.getTotal());
            pageData.setPageNo(startPage.getPageNum());
            pageData.setPageSize(startPage.getPageSize());
        }
        return pageData;
    }


    public void save(BusinessData entity) {
        FormDefinition definition = formDefinitionService.getCompleteDataByName(entity.getDefinition());
        if (definition != null) {
            entity.configDefinition(definition);
            entity.preInsert();
            //存储前的数据检查
            DataValidationHelper.validation(entity.getColumnList(), entity.getData());
            int flag = dao.insert(entity);
            entity.postInsert(flag);
            // 级联更新一对多关系表数据
            triggerRelationData(entity, false, true);
        }
    }

    public void batchSave(List<BusinessData> list) {
        list.forEach(d -> {
            d.preInsert();
        });
        dao.batchInsert(list);
    }

    public void update(BusinessData entity) {
        FormDefinition definition = formDefinitionService.getCompleteDataByName(entity.getDefinition());
        if (definition != null) {
            entity.configDefinition(definition);
            entity.preUpdate();
            //存储前的数据检查
            DataValidationHelper.validation(entity.getColumnList(), entity.getData());
            int flag = dao.update(entity);
            entity.postUpdate(flag);
            // 级联更新一对多关系表数据
            triggerRelationData(entity, true, true);
        }
    }

    public void delete(BusinessData entity) {
        FormDefinition definition = formDefinitionService.getCompleteDataByName(entity.getDefinition());
        if (definition != null) {
            entity.configDefinition(definition);
            dao.delete(entity);
            // 级联更新一对多关系表数据
            triggerRelationData(entity, true, false);
        }
    }

    /**
     * 加载关联数据
     *
     * @param entity
     */
    private void loadRelationData(BusinessData entity) {
        List<BusTableRel> children = entity.getRelChildren(entity.getRelation(), BpmConstant.BPM_BUSINESS_TABLE_REL_TYPE_ONE_TO_MANY);
        for (BusTableRel rel : children) {
            BusinessData many = new BusinessData();
            many.configDefinition(rel);
            List<BusTableRelFk> fks = rel.getFks();
            for (BusTableRelFk fk : fks) {
                if (StringUtils.equals(fk.getType(), BpmConstant.BPM_BUSINESS_TABLE_REL_FK_TYPE_MAIN_FK)) {
                    many.addFilter(new Filter(fk.getJoinTableKey(), "=", entity.getData().get(fk.getParentKey())));
                } else {
                    many.addFilter(new Filter(fk.getJoinTableKey(), "=", fk.getParentKey()));
                }
            }
            List<Map<String, Object>> listData = dao.findList(many);
            entity.getData().put(many.getBusinessTable().getAlias() + "List", listData);
        }
        // 加载附件数据
        if (!entity.attachmentFields().isEmpty()) {
            AttachmentMapping attachmentMapping = new AttachmentMapping();
            attachmentMapping.addFilter(new Filter("businessId", "=", entity.getPrimaryKey()));
            List<AttachmentMapping> list = remoteEndpoint.executePost(projectConfig.getOpenDocumentServer(), "/attachment/mapping/all", attachmentMapping, AttachmentMapping.class);
            if (list != null && !list.isEmpty()) {
                for (AttachmentMapping mapping : list) {
                    List<Attachment> attachmentList = (List<Attachment>) entity.getData().get(mapping.getFieldName());
                    if (attachmentList == null) {
                        attachmentList = Lists.newArrayList();
                        entity.getData().put(mapping.getFieldName(), attachmentList);
                    }
                    attachmentList.add(mapping.getAttachment());
                }
            }
        }


    }

    /**
     * 级联更新一对多的关系数据
     *
     * @param entity
     * @param delete
     * @param save
     */
    private void triggerRelationData(BusinessData entity, boolean delete, boolean save) {
        if (delete) {
            List<BusTableRel> children = entity.getRelChildren(entity.getRelation(), BpmConstant.BPM_BUSINESS_TABLE_REL_TYPE_ONE_TO_MANY);
            for (BusTableRel rel : children) {
                // 保存之前先执行删除操作
                triggerDelete(rel, entity);
            }
            // 删除附件
            if (!entity.attachmentFields().isEmpty()) {
                AttachmentMapping attachmentMapping = new AttachmentMapping();
                attachmentMapping.setBusinessId(entity.getPrimaryKey());
                remoteEndpoint.executePost(projectConfig.getOpenDocumentServer(), "/attachment/mapping/deleteByBusinessId", attachmentMapping, AttachmentMapping.class);
            }
        }
        if (save) {
            List<BusTableRel> children = entity.getRelChildren(entity.getRelation(), BpmConstant.BPM_BUSINESS_TABLE_REL_TYPE_ONE_TO_MANY);
            for (BusTableRel rel : children) {
                triggerSave(rel, entity);
            }
            // 加载附件数据
            List<BusinessColumn> columns = entity.attachmentFields();
            if (!columns.isEmpty()) {
                List<AttachmentMapping> mappingList = Lists.newArrayList();
                for (BusinessColumn column : columns) {
                    List<Map<String, Object>> attachmentList = (List<Map<String, Object>>) entity.getData().get(column.getFieldName());
                    if (attachmentList != null && !attachmentList.isEmpty()) {
                        for (Map<String, Object> attachment : attachmentList) {
                            AttachmentMapping mapping = new AttachmentMapping();
                            mapping.setBusinessId(entity.getPrimaryKey());
                            mapping.setFieldName(column.getFieldName());
                            mapping.setAttachment(MapUtils.toBean(attachment, Attachment.class));
                            mappingList.add(mapping);
                        }
                    }
                }
                if (!mappingList.isEmpty()) {
                    remoteEndpoint.executePost(projectConfig.getOpenDocumentServer(), "/attachment/mapping/batch/save", mappingList, AttachmentMapping.class);
                }
            }
        }
    }

    private void triggerSave(BusTableRel rel, BusinessData entity) {
        String manyKey = rel.getBusinessTable().getAlias() + "List";
        Map<String, Object> data = entity.getData();
        if (data.containsKey(manyKey)) {
            List<Map<String, Object>> manyList = (List<Map<String, Object>>) data.get(manyKey);
            List<BusinessData> dataList = Lists.newArrayList();
            for (Map<String, Object> map : manyList) {
                List<BusTableRelFk> fks = rel.getFks();
                BusinessData manyData = new BusinessData();
                manyData.setData(map);
                manyData.configDefinition(rel);
                for (BusTableRelFk fk : fks) {
                    if (StringUtils.equals(fk.getType(), BpmConstant.BPM_BUSINESS_TABLE_REL_FK_TYPE_MAIN_FK)) {
                        map.put(fk.getJoinTableKey(), data.get(fk.getParentKey()));
                    } else {
                        map.put(fk.getJoinTableKey(), fk.getParentKey());
                    }
                }

                dataList.add(manyData);
            }
            batchSave(dataList);

        }
    }

    private void triggerDelete(BusTableRel rel, BusinessData entity) {
        BusinessData many = new BusinessData();
        Map<String, Object> data = entity.getData();
        many.configDefinition(rel);
        List<BusTableRelFk> fks = rel.getFks();
        List<String> del = Lists.newArrayList();
        for (BusTableRelFk fk : fks) {
            if (StringUtils.equals(fk.getType(), BpmConstant.BPM_BUSINESS_TABLE_REL_FK_TYPE_MAIN_FK)) {
                del.add(many.getColumnByFieldName(fk.getJoinTableKey()) + "='" + data.get(fk.getParentKey()) + "'");
            } else {
                del.add(many.getColumnByFieldName(fk.getJoinTableKey()) + "='" + fk.getParentKey() + "'");
            }
        }
        many.setDelKey(StringUtils.join(del, " and "));
        dao.deleteByFilter(many);

    }

    public void exportData(BusinessData entity) {
        FormDefinition definition = formDefinitionService.getCompleteDataByName(entity.getDefinition());
        if (definition != null) {
//            entity.configDefinition(definition);
            IexpTask task = IexpTask.createNewExpTask("businessDataExport", JsonMapper.toJsonString(entity));
            task.setName(definition.getDescription() + "数据导出");
            // 存储后台任务
            remoteEndpoint.executePost(projectConfig.getOpenTaskServer(), "/iexp/task/save", task, IexpTask.class);
        }
    }

    /**
     * 导出模板
     *
     * @param entity
     * @param response
     */
    public void importTemplate(BusinessData entity, HttpServletResponse response) {
        FormDefinition definition = formDefinitionService.getCompleteDataByName(entity.getDefinition());
        if (definition != null) {
            //TODO 这里需要远程调用task-server来生成文件
////            entity.configDefinition(definition);
//            IExportModel imp = businessDataTemplate.getExportModel(entity, "imp");
//            try {
//                new ExportTemplateExcelExecutor()
//                        .initByModelAndData(imp, MapData.instance().put("list", Lists.newArrayList()).data())
//                        .buildExcel()
//                        .write(response, definition.getDescription() + "导入模板").dispose();
//            } catch (Exception e) {
//                logger.error(e.getMessage(), e);
//                throw new ServiceException(e);
//            }
        }
    }

    public Object importData(BusinessData entity, MultipartFile file) {
        Attachment attachment = formDefinitionService.storeFile(file);
        FormDefinition definition = formDefinitionService.getCompleteDataByName(entity.getDefinition());
        Map<String, Object> param = createParam(definition);
        if (definition != null) {
//            entity.configDefinition(definition);
            IexpTask task = IexpTask.createNewImpTask("businessDataImport", JsonMapper.toJsonString(param), attachment.getFileName());
            task.setName(definition.getDescription() + "数据导入");
            task.setAttachment(attachment);
            // 存储后台任务
            remoteEndpoint.executePost(projectConfig.getOpenTaskServer(), "/iexp/task/save", task, IexpTask.class);
        }
        return entity;
    }

    private Map<String, Object> createParam(FormDefinition definition) {
        FormConfig formConfig = definition.coverConfig();
        List<ColumnConfig> collect = formConfig.getColumnList().stream().filter(c -> StringUtils.equals(BpmConstant.SYS_YES, c.getImp())).collect(Collectors.toList());
        Map<String, Object> map = new HashMap<>();
        List<Map<String, Object>> entitys = new ArrayList<>();
        // 配置封面导入信息
        entitys.add(new HashMap<String, Object>() {{
            put("sheetIndexOrName", 0);// 设置sheet页名称
            put("importEntityClass", Map.class);// 设置数据解析的类
            // 设置解析区域
            put("startColumn", new String("A"));// 设置数开始列
            put("endColumn", new String(ExcelUtils.toExcelName(collect.size() - 1)));// 设置结束列
            put("startRow", 3);// 设置开始行(从1开始)
//            put("endRow", 19);// 设置结束行
        }});
        map.put("sheetAndEntitys", entitys);//放置所有需要导入的sheet
        map.put("definitionName", definition.getName());
        return map;
    }

//    public static void main(String[] args) {
//        IExportModel imp = new IExportModel() {
//            @Override
//            public String getTitle() {
//                return "Demo";
//            }
//
//            @Override
//            public List<? extends IExportField> getExportFieldList() {
//                return new ArrayList<IExportField>(){{
//                    add(new IExportField() {
//                        @Override
//                        public String getTitle() {
//                            return "时间";
//                        }
//
//                        @Override
//                        public String getFieldName() {
//                            return "date";
//                        }
//
//                        @Override
//                        public Class<?> getFieldType() {
//                            return null;
//                        }
//
//                        @Override
//                        public String getDictType() {
//                            return null;
//                        }
//
//                        @Override
//                        public String getDictField() {
//                            return null;
//                        }
//
//                        @Override
//                        public String getFormat() {
//                            return null;
//                        }
//                    });
//                    add(new IExportField() {
//                        @Override
//                        public String getTitle() {
//                            return "金钱";
//                        }
//
//                        @Override
//                        public String getFieldName() {
//                            return "money";
//                        }
//
//                        @Override
//                        public Class<?> getFieldType() {
//                            return null;
//                        }
//
//                        @Override
//                        public String getDictType() {
//                            return null;
//                        }
//
//                        @Override
//                        public String getDictField() {
//                            return null;
//                        }
//
//                        @Override
//                        public String getFormat() {
//                            return "##.##########";
//                        }
//                    });
//                }};
//            }
//        };
//        try {
//            List<Map<String,Object>> dataList=Lists.newArrayList();
//            dataList.add(new HashMap<String,Object>(){{
//                put("date",new Date());
//                put("money",new BigDecimal("41150.442477"));
//            }});
//            new ExportTemplateExcelExecutor()
//                    .initByModelAndData(imp, MapData.instance().put("list", dataList).data())
//                    .buildExcel()
//                    .writeFile("C:\\TEMP\\demo.xlsx").dispose();
//        } catch (Exception e) {
//            throw new ServiceException(e);
//        }
//    }

}
